﻿/*
 				________________________________COPYRIGHT_______________________________________
				Die Veröffentlichung dieses Objektes ist Illegal und wird strafrechtlich verfolgt
				werden. Sollte es zu einer Veröffentlichung kommen werden wir die Daten des
				Herrausgebers fündig machen und Anzeige erstatten. Desweiteren ist
				auch jeglicher Besitz dieses Objektes Illegal und kann ebenfalls als Grund für
				eine Anzeige verwendet werden.
				Ausnahmen der veröffentlichung und verleihung gelten nur wenn der Grundbesitzer
				diese durchführt.
				Die Uhrheberrechte dieses Objektes liegen der Entwickler Gruppe CyberScripting vor. 
                © 2011.
 */

using System;
using System.Collections.Generic;
using LibNoise.Xna.Generator;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using cubeworld.Blocks;

namespace cubeworld.World
{
    internal class ChunkGenerator
    {
        private readonly Perlin _perlinNouse;
        private readonly int startX;
        private readonly int startZ;
        private Biom biom;

        private float tempI, tempI2;

        public ChunkGenerator(Biom biom, int startX, int startZ)
        {
            this.biom = biom;
            this.startX = startX;
            this.startZ = startZ;
            _perlinNouse = new Perlin();
            _perlinNouse.Frequency = 0.03f;
            _perlinNouse.OctaveCount = 1;
        }

        public Block createBlockFromID(int id, float x, float y, float z)
        {
            Block block;
            switch (id)
            {
                case 0:
                    block = new Air(new Vector3(x, y, z));
                    break;
                case 1:
                    block = new MarsRock(new Vector3(x, y, z));
                    break;
                case 2:
                    block = new Stone(new Vector3(x, y, z));
                    break;
                case 3:
                    block = new LavaStone(new Vector3(x, y, z));
                    break;
                case 4:
                    block = new BrimStone(new Vector3(x, y, z));
                    break;
                case 64:
                    block = new Bedrock(new Vector3(x, y, z));
                    break;
                default:
                    throw new Exception("Unknow Block ID in Biom");
            }
            return block;
        }

        public Texture2D CreateStaticMap(int resolution)
        {
            var noisyColors = new Color[resolution*resolution];
            for (int x = 0; x < resolution; x++)
                for (int y = 0; y < resolution; y++)
                {
                    int rand = Data.random.Next(200, 255);
                    noisyColors[x + y*resolution] = new Color(rand, 0, 0);
                }

            var noiseImage = new Texture2D(MainGame.Device, resolution, resolution, false, SurfaceFormat.Color);
            noiseImage.SetData(noisyColors);
            return noiseImage;
        }

        public bool isBlockVisible(Block b, Block[,,] blocks)
        {
            int founds = 0;
            try
            {
               /* if (blocks[(int)b.Position.X - 1, (int)b.Position.Y, (int)b.Position.Z] != null) { founds++; }
                if (blocks[(int)b.Position.X + 1, (int)b.Position.Y, (int)b.Position.Z] != null) { founds++; }
                if (blocks[(int)b.Position.X, (int)b.Position.Y - 1, (int)b.Position.Z] != null) { founds++; }
                if (blocks[(int)b.Position.X, (int)b.Position.Y + 1, (int)b.Position.Z] != null) { founds++; }
                if (blocks[(int)b.Position.X, (int)b.Position.Y, (int)b.Position.Z - 1] != null) { founds++; }
                if (blocks[(int)b.Position.X, (int)b.Position.Y, (int)b.Position.Z + 1] != null) { founds++; }*/
            }
            catch
            {
                
            }
            return founds < 6;
        }

        public Block[,,] Generate(int chunkWidth)
        {
            Block[, ,] blocks = new Block[16, 70, 16];
            int _x = 0, _z = 0, i = 0;
            for (float x = startX; x < (startX + chunkWidth); x++)
            {
                _z = 0;
                for (float z = startZ; z < (startZ + chunkWidth); z++)
                {
                    double val = 30+_perlinNouse.GetValue(x, 1, z)*20;
                    for (int y = 0; y < val; y++)
                    {
                        Block block = createBlockFromID((int) BlockType.stone, x, y - 64, z);
                        block.visible = true;
                        i++;
                        blocks[_x, Convert.ToInt32(y), _z] = block;
                    }

                    for (int _y = 0; _y < 70; _y++)
                    {
                        if(blocks[_x, _y, _z] != null) 
                            blocks[_x, _y, _z].visible = isBlockVisible(blocks[_x, _y, _z], blocks);
                    }

                    


                    /*

                    //below
                    tempI = Data.random.Next(0, 100);
                    tempI2 = 0;
                    for (int i = 0; i < biom.Below.Count; i++)
                    {
                        tempI2 += biom.Below[i].chance;
                        if (tempI < tempI2)
                        {
                            Block block = createBlockFromID(biom.Below[i].id, x,-65.0f, z);
                            blocks.Add(block);
                            blocks[blocks.Count - 1].visible = true;
                            Data.world.visibleBlocks.Add(block);
                            break;
                        }
                    }
                    //bottom
                    for (float bottomY = -64f; bottomY < -29f; bottomY++)
                    {
                        tempI = Data.random.Next(0, 100);
                        tempI2 = 0;
                        for (int i = 0; i < biom.Bottom.Count; i++)
                        {
                            tempI2 += biom.Bottom[i].chance;
                            if (tempI < tempI2)
                            {
                                Block block = createBlockFromID(biom.Bottom[i].id, x, bottomY, z);
                                blocks.Add(block);
                                blocks[blocks.Count - 1].visible = false;
                                break;
                            }
                        }
                    }
                    //middle
                    for (float middleY = -29f; middleY < -9; middleY++)
                    {
                        tempI = Data.random.Next(0, 100);
                        tempI2 = 0;
                        for (int i = 0; i < biom.Middle.Count; i++)
                        {
                            tempI2 += biom.Middle[i].chance;
                            if (tempI < tempI2)
                            {
                                Block block = createBlockFromID(biom.Middle[i].id, x, middleY, z);
                                blocks.Add(block);
                                blocks[blocks.Count - 1].visible = false;
                                break;
                            }
                        }
                    }

                    */
                    /* //surface
                    for (float surfaceY = -10; surfaceY < 10; surfaceY++)
                    {
                        tempI = Data.random.Next(0, 100);
                        tempI2 = 0;
                        for (int i = 0; i < biom.Surface.Count; i++)
                        {
                            tempI2 += biom.Surface[i].chance;
                            if (tempI < tempI2)
                            {
                                Block block = createBlockFromID(biom.Surface[i].id, x, surfaceY, z);
                                blocks.Add(block);
                                blocks[blocks.Count - 1].visible = false;
                                if (surfaceY == 9)
                                {
                                    blocks[blocks.Count - 1].visible = true;
                                    Data.world.visibleBlocks.Add(block);
                                }
                                break;
                            }
                        }
                }*/

                    /*Montains
                    Texture2D tex = this.CreateStaticMap(chunkWidth);
                    Color[,] color = TextureTo2DArray(tex);
                    for (int x2 = 0; x2 < tex.Width; x2++)
                    {
                        for (int z2 = 0; z2 < tex.Height; z2++)
                        {
                            Byte hell = color[x2, z2].R;
                            float heightY = roundTo1(hell / 5.0f);
                            heightY += 10;
                            Data.world.blocks.Add(createBlockFromID(biom.Surface[0].id, x2 + startX, heightY, z2 + startZ));
                        }
                    }*/
                    _z++;
                }
                _x++;
            }
            #if (DEBUG)
            Console.WriteLine(i + " Blocks created");
            #endif
            return blocks;
        }

        public float roundTo1(float a)
        {
            float r = (a - (5*((a/5) - (int) (a/5))))/5;
            //Data.test = r;
            return r;
        }

        private Color[,] TextureTo2DArray(Texture2D texture)
        {
            var colors1D = new Color[texture.Width*texture.Height];
            texture.GetData(colors1D);
            var colors2D = new Color[texture.Width,texture.Height];
            for (int x = 0; x < texture.Width; x++)
                for (int y = 0; y < texture.Height; y++)
                    colors2D[x, y] = colors1D[x + y*texture.Width];

            return colors2D;
        }
    }
}